#include "../Include/SoundSystem.h"

#pragma comment( lib, "FMODex_vc.lib" )

SoundSystem *SoundSystem::m_pInstance = NULL;

Sound::Sound( void )
	: m_pSound( NULL ), m_pChannel( NULL )
{
	m_pSoundSystem = SoundSystem::GetInstance();
}

Sound::Sound( const CHAR *pFilename, Pulse::BOOL bMusic )
	: m_pSoundSystem( NULL )
{
	m_pSoundSystem = SoundSystem::GetInstance();
	m_pSound = m_pSoundSystem ->LoadFile( pFilename, bMusic );

	if ( m_pSound )
		m_name = pFilename;
}

Sound::~Sound( void )
{
	if ( m_pSound )
		Release();
}

Pulse::BOOL Sound::LoadSound( const CHAR *pFilename )
{
	if ( IsLoaded() )
		Release();

	m_pSound = m_pSoundSystem ->LoadFile( pFilename );

	if ( m_pSound )
		m_name = pFilename;

	return m_pSound != NULL;
}

Pulse::BOOL Sound::LoadMusic( const CHAR *pFilename )
{
	if ( IsLoaded() )
		Release();

	m_pSound = m_pSoundSystem ->LoadFile( pFilename, TRUE );

	if ( m_pSound )
		m_name = pFilename;

	return m_pSound != NULL;
}

void Sound::SetLoop( Pulse::BOOL bLoop )
{
	if ( bLoop )
		m_pSound->setMode( FMOD_LOOP_NORMAL );
	else
		m_pSound->setMode( FMOD_LOOP_OFF );
}

void Sound::Play( void )
{
	m_pChannel = m_pSoundSystem->PlaySound( this );
}

void Sound::Pause( void )
{
	if ( !m_pChannel )
		return;

	m_pChannel->setPaused( true );

}

void Sound::Resume( void )
{
	if ( !m_pChannel )
		return;

	m_pChannel->setPaused( false );
}

void Sound::Stop( void )
{
	if ( !m_pChannel )
		return;

	m_pChannel->stop();
}

Pulse::BOOL Sound::IsPlaying( void )
{
	if ( !m_pChannel )
		return false;

	bool bPlaying;
	m_pChannel->isPlaying( &bPlaying );

	return bPlaying;
}

void Sound::Release( void )
{
	if ( m_pSound )
		m_pSound->release();

	m_pSound = NULL;
	m_pChannel = NULL;
	m_name = "";
}

////////////////////////////

SoundSystem::~SoundSystem( void )
{
	
}

SoundSystem * SoundSystem::GetInstance( void )
{
	if ( m_pInstance )
		return m_pInstance;

	m_pInstance = new SoundSystem;

	return m_pInstance;
}

void SoundSystem::DeleteInstance( void )
{
	if ( m_pInstance )
	{
		delete m_pInstance;
		m_pInstance = 0;
	}
}

bool SoundSystem::Initialize( INT numChannels )
{
	if ( m_pFMODSystem )
		return false;

	FMOD::System_Create( &m_pFMODSystem );

	if ( m_pFMODSystem == NULL )
		return false;

	int result = m_pFMODSystem->init( numChannels, FMOD_INIT_NORMAL, NULL );

	m_numChannels = numChannels;
	m_pChannelPairs = new ChannelSoundPair[numChannels];

	for ( INT i = 0; i < numChannels; ++i )
	{
		m_pFMODSystem->getChannel( i, &m_pChannelPairs[i].pChannel );
	}

	return result == FMOD_OK;
}

void SoundSystem::Shutdown( void )
{
	if ( m_pFMODSystem )
	{
		m_FMODSoundMap.clear();
		delete [] m_pChannelPairs;
		m_numChannels = 0;

		m_pFMODSystem->close();
		m_pFMODSystem->release();
		m_pFMODSystem = NULL;
	}
}

void SoundSystem::Update( void )
{
	FMOD::Channel *pChannel;
	bool bPaused, bPlaying;

	for ( Pulse::SIZE_T i = 0; i < m_numChannels; ++i )
	{
		if ( m_pChannelPairs[i].pSound == NULL )
			continue;

		pChannel = m_pChannelPairs[i].pChannel;
		pChannel->getPaused( &bPaused );
		pChannel->isPlaying( &bPlaying );

		if ( bPlaying == false && bPaused == false )
		{
			m_pChannelPairs[i].pSound->RemoveChannel();
			m_pChannelPairs[i].pSound = NULL;
		}
	}
}

SoundSystem::SoundSystem( void )
	: m_pFMODSystem( 0 ), m_pChannelPairs( NULL )
{

}

FMOD::Sound * SoundSystem::LoadFile( const char *pFilename, Pulse::BOOL bMusic )
{
	if ( m_FMODSoundMap.find( pFilename ) != m_FMODSoundMap.end() )
		return m_FMODSoundMap[pFilename];

	// Load sound file
	FMOD::Sound *pSound;
	UINT mode = FMOD_HARDWARE | FMOD_2D;
	mode |= bMusic ? FMOD_UNIQUE : 0;
	FMOD_RESULT result = m_pFMODSystem->createSound( pFilename, mode, 0, &pSound );

	if ( result != FMOD_OK )
		return NULL;

	m_FMODSoundMap[ pFilename ] = pSound;

	return pSound;
}

FMOD::Channel * SoundSystem::PlaySound( Sound *pSound )
{
	FMOD::Channel *pChannel;
	int index;
	m_pFMODSystem->playSound( FMOD_CHANNEL_FREE, pSound->GetFMODSound(), false, &pChannel );
	pChannel->getIndex( &index );
	m_pChannelPairs[index].pSound = pSound;

	return pChannel;
}
